#include "mainwindow.h"
#include "qdesigner.h"
#include "qdockwidget.h"

#include "designerworkbench.h"
#include "designer_actions.h"
#include "designer_toolwindow.h"
#include "designer_settings.h"
#include "qttoolbardialog.h"
#include "designer_formwindow.h"

#include <QtDesigner/QDesignerComponents>
#include <QtDesigner/QDesignerFormEditorInterface>
#include <QToolBar>
#include <QMdiArea>
#include <QMdiSubWindow>
//#include <QEvent>
#include <QMouseEvent>

#include <QDebug>


typedef QList<QAction *> ActionList;

static void addActionsToToolBar(const ActionList &actions, QToolBar *t)
{
    const ActionList::const_iterator cend = actions.constEnd();
    for (ActionList::const_iterator it = actions.constBegin(); it != cend; ++it) {
        QAction *action = *it;
        if (action->property(QDesignerActions::defaultToolbarPropertyName).toBool())
            t->addAction(action);
    }
}
static QToolBar *createToolBar(const QString &title, const QString &objectName, const ActionList &actions)
{
    QToolBar *rc = new QToolBar;
    rc->setObjectName(objectName);
    rc->setWindowTitle(title);
    addActionsToToolBar(actions, rc);
    //qDebug()<<title<<objectName<<actions.size();
    return rc;
}

// ---------------- MainWindowBase

MainWindowBase::MainWindowBase(QWidget *parent, Qt::WindowFlags flags) :
    QMainWindow(parent, flags),
    m_policy(AcceptCloseEvents)
{
#ifndef Q_WS_MAC
    setWindowIcon(qDesigner->windowIcon());
#endif
}

void MainWindowBase::closeEvent(QCloseEvent *e)
{
    switch (m_policy) {
    case AcceptCloseEvents:
        QMainWindow::closeEvent(e);
        break;
      case EmitCloseEventSignal:
        emit closeEventReceived(e);
        break;
    }
}

QList<QToolBar *>  MainWindowBase::createToolBars(const QDesignerActions *actions)
{
    // Note that whenever you want to add a new tool bar here, you also have to update the default
    // action groups added to the toolbar manager in the mainwindow constructor
    QList<QToolBar *> rc;
    rc.push_back(createToolBar(tr("File"), QLatin1String("fileToolBar"), actions->fileActions()->actions()));
    //rc.push_back(createToolBar(tr("Edit"), QLatin1String("editToolBar"),  actions->editActions()->actions()));
    rc.push_back(createToolBar(tr("Tools"), QLatin1String("toolsToolBar"), actions->toolActions()->actions()));
    rc.push_back(createToolBar(tr("Form"), QLatin1String("formToolBar"), actions->formActions()->actions()));
    rc.push_back(createToolBar(tr("Project"), QLatin1String("projectToolBar"), actions->projectActions()->actions()));

    return rc;
}

QString MainWindowBase::mainWindowTitle()
{
    return tr("Qt Designer");
}

// Use the minor Qt version as settings versions to avoid conflicts
int MainWindowBase::settingsVersion()
{
    const int version = QT_VERSION;
    return (version & 0x00FF00) >> 8;
}

static inline QWidget *createWidgetBox(QDesignerFormEditorInterface *core, QWidget *parent = 0)
{
    QDesignerWidgetBoxInterface *widget = QDesignerComponents::createWidgetBox(core, parent);
    core->setWidgetBox(widget);

    return (QWidget*)widget;
}



// ------------- ToolBarManager:

static void addActionsToToolBarManager(const ActionList &al, const QString &title, QtToolBarManager *tbm)
{
    const ActionList::const_iterator cend = al.constEnd();
    for (ActionList::const_iterator it = al.constBegin(); it != cend; ++it)
        tbm->addAction(*it, title);
}

ToolBarManager::ToolBarManager(QMainWindow *mainWindow,
                                         QMenu *toolBarMenu,
                                         const QDesignerActions *actions,
                                         const QList<QToolBar *> &toolbars,
                                         const QList<QDesignerToolWindow*> &toolWindows) :
    QObject(mainWindow),
    m_configureableMainWindow(mainWindow),
    m_toolBarMenu(toolBarMenu),
    m_manager(new QtToolBarManager(this)),
    m_configureAction(new QAction(tr("Configure Toolbars..."), this)),
    m_toolbars(toolbars)
{
    m_configureAction->setMenuRole(QAction::NoRole);
    m_configureAction->setObjectName(QLatin1String("__qt_configure_tool_bars_action"));
    connect(m_configureAction, SIGNAL(triggered()), this, SLOT(configureToolBars()));

    m_manager->setMainWindow(mainWindow);

    foreach(QToolBar *tb, m_toolbars) {
        const QString title = tb->windowTitle();
        m_manager->addToolBar(tb, title);
        addActionsToToolBarManager(tb->actions(), title, m_manager);
    }

    //addActionsToToolBarManager(actions->windowActions()->actions(), tr("Window"), m_manager);
    //addActionsToToolBarManager(actions->helpActions()->actions(), tr("Help"), m_manager);


    const QString dockTitle = tr("Dock views");
    foreach (QDesignerToolWindow *tw, toolWindows) {
        if (QAction *action = tw->action())
            m_manager->addAction(action, dockTitle);
    }

    QString category(tr("File"));
    foreach(QAction *action, actions->fileActions()->actions())
        m_manager->addAction(action, category);

    category = tr("Edit");
    foreach(QAction *action, actions->editActions()->actions())
        m_manager->addAction(action, category);

    category = tr("Tools");
    foreach(QAction *action, actions->toolActions()->actions())
        m_manager->addAction(action, category);

//    category = tr("Form");
//    foreach(QAction *action, actions->formActions()->actions())
//        m_manager->addAction(action, category);

    m_manager->addAction(m_configureAction, tr("Toolbars"));
    updateToolBarMenu();
}

// sort function for sorting tool bars alphabetically by title [non-static since called from template]

bool toolBarTitleLessThan(const QToolBar *t1, const QToolBar *t2)
{
    return t1->windowTitle() < t2->windowTitle();
}

void ToolBarManager::updateToolBarMenu()
{
    // Sort tool bars alphabetically by title
    qStableSort(m_toolbars.begin(), m_toolbars.end(), toolBarTitleLessThan);
    // add to menu
    m_toolBarMenu->clear();
    foreach (QToolBar *tb,  m_toolbars)
        m_toolBarMenu->addAction(tb->toggleViewAction());
    m_toolBarMenu->addAction(m_configureAction);
}

void ToolBarManager::configureToolBars()
{
    QtToolBarDialog dlg(m_configureableMainWindow);
    dlg.setWindowFlags(dlg.windowFlags() & ~Qt::WindowContextHelpButtonHint);
    dlg.setToolBarManager(m_manager);
    dlg.exec();
    updateToolBarMenu();
}

QByteArray ToolBarManager::saveState(int version) const
{
    return m_manager->saveState(version);
}

bool ToolBarManager::restoreState(const QByteArray &state, int version)
{
    return m_manager->restoreState(state, version);
}


// ---------- DockedMainWindow

DockedMainWindow::DockedMainWindow(QDesignerWorkbench *wb,
                              QMenu *toolBarMenu,
                              const DesignerToolWindowList &toolWindows)//: m_toolBarManager(0)
{
    setObjectName(QLatin1String("MDIWindow"));
    setWindowTitle("ScriptDesigner");

    const QList<QToolBar *> toolbars = createToolBars(wb->actionManager());
    foreach (QToolBar *tb, toolbars)
        addToolBar(tb);
    QMdiArea *dma = new QMdiArea();
    setCentralWidget(dma);
    connect(dma, SIGNAL(subWindowActivated(QMdiSubWindow*)),
            this, SLOT(slotSubWindowActivated(QMdiSubWindow*)));

    m_toolBarManager = new ToolBarManager(this, toolBarMenu, wb->actionManager(), toolbars, toolWindows);

}

QMdiArea* DockedMainWindow::mdiArea() const
{
    return static_cast<QMdiArea *>(centralWidget());
}

void DockedMainWindow::slotSubWindowActivated(QMdiSubWindow* subWindow)
{
    if (subWindow) {
        QWidget *widget = subWindow->widget();
        if (QDesignerFormWindow *fw = qobject_cast<QDesignerFormWindow*>(widget)) {
            emit formWindowActivated(fw);
            mdiArea()->setActiveSubWindow(subWindow);
        }
    }
}

DockedMainWindow::DockWidgetList DockedMainWindow::addToolWindows(const DesignerToolWindowList &tls)
{
    DockWidgetList rc;
    foreach (QDesignerToolWindow *tw, tls) {
        QDockWidget *dockWidget = new QDockWidget;
        dockWidget->setObjectName(tw->objectName() + QLatin1String("_dock"));
        dockWidget->setWindowTitle(tw->windowTitle());
        addDockWidget(tw->dockWidgetAreaHint(), dockWidget);
        dockWidget->setWidget(tw);
        rc.push_back(dockWidget);
    }
    return rc;
}
// Settings consist of MainWindow state and tool bar manager state
void DockedMainWindow::restoreSettings(const QDesignerSettings &s, const DockWidgetList &dws, const QRect &desktopArea)
{
    const int version = settingsVersion();
    //m_toolBarManager->restoreState(s.toolBarsState(), version);

    // If there are no old geometry settings, show the window maximized
    s.restoreGeometry(this, QRect(desktopArea.topLeft(), QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)));

    const QByteArray mainWindowState = s.mainWindowState();
    const bool restored = !mainWindowState.isEmpty() && restoreState(mainWindowState, version);
    if (!restored) {
        // Default: Tabify less relevant windows bottom/right.
        tabifyDockWidget(dws.at(QDesignerToolWindow::SignalSlotEditor),
                         dws.at(QDesignerToolWindow::ActionEditor));
    }
}

void DockedMainWindow::saveSettings(QDesignerSettings &s) const
{
    const int version = settingsVersion();
   // s.setToolBarsState(DockedMode, m_toolBarManager->saveState(version));
    s.saveGeometryFor(this);
    s.setMainWindowState(saveState(version));
}
// Create a MDI subwindow for the form.
QMdiSubWindow *DockedMainWindow::createMdiSubWindow(QWidget *fw, const QKeySequence &designerCloseActionShortCut)
{
    QMdiSubWindow *rc = mdiArea()->addSubWindow(fw, Qt::Window | Qt::WindowShadeButtonHint | Qt::WindowSystemMenuHint | Qt::WindowTitleHint);
    // Make action shortcuts respond only if focused to avoid conflicts with
    // designer menu actions
    if (designerCloseActionShortCut == QKeySequence(QKeySequence::Close)) {
        const ActionList systemMenuActions = rc->systemMenu()->actions();
        if (!systemMenuActions.empty()) {
            const ActionList::const_iterator cend = systemMenuActions.constEnd();
            for (ActionList::const_iterator it = systemMenuActions.constBegin(); it != cend; ++it) {
                if ( (*it)->shortcut() == designerCloseActionShortCut) {
                    (*it)->setShortcutContext(Qt::WidgetShortcut);
                    break;
                }
            }
        }
    }
    return rc;
}

bool DockedMainWindow::eventFilter(QObject *, QEvent *event)
{   if (event->type() == QEvent::ContextMenu) {
        QMouseEvent *mev = static_cast<QMouseEvent*>(event);
        qDebug()<< mev << "ContextMenu";
        return true;
    }
    //qDebug()<<event<<event->type();
    return false;
}
